<script>
import { Draggable } from 'draggable-vue-directive'
import mutil        from '../utils/mutil';
// import { PageItemCommonStyle } from 'jzl-web-components';
import NodeDataValue from './ele/node-data-value';
import NodeFormulaRender from './ele/node-formula-render';
import BuilderNodesProp from './builder-nodes-prop';
import BuilderNodesAdd  from "./builder-nodes-add"
import BuilderNodesAddTools  from "./builder-nodes-add-tools"
import BuilderNodesLowcode from "./builder-nodes-lowcode";
import BuilderNodePropext from './builder-node-propext';
import BuilderCompsCloud from './builder-comps-cloud';
import PageItemPicker   from './pages/page-item-picker';

// import TPL_NODES from '../utils/tpl-nodes';
import tplCate      from '../utils/tpl-cate'

export default {
  name: "builder-nodes",
  props: {
    pageType: [ String, Number ],
    currentItem: Object,
    currentPage: Object,
    currentItemElCode: String,
    currentItems: Array,
    elemNodes: {
      type: [ Array, Object ],
      default: []
    },
    pageWidth: {
      type: Number,
      default: 1920
    },
    pageHeight: {
      type: Number,
      default: 1080
    }
  },
  data() {
    return {
      nodeTreeSetting: {
        label: 'name',
        // children: 'childs'
      },
      collapse: false,
      currentEleData: {},
      currentNode: {},
      expandKeys: [],
      popData: null,
      nodesPropShow: true,
      propTab: 'style',
      moving: false,
      nodeTreeDragProp: {
        boundingElement: document.body,
        handle: null,
        onPositionChange: this.onPosChanged
      },
      tempExpand: false,
      hoverExpand: false,
      panelFixed: true,
      tempExpandTimer: null,
      hoverExpandTimer: null,
      isNodeHover: false,
      hoverTimeout: null,

      tplCate: tplCate,
      compAddPanelShow: false,

      nodeActionPopVisible: false,
      nodeValuePopVisible: false,
      nodeEventPopVisible: false,
      nodeLowcodePopVisible: false,
      nodeFormulaPopVisible: false,

      compPanelName: "选择云组件",
      compPanelShow: false,
      isCreateMicroComp: false,

      pageItemSelectWinShow: false
    }
  },
  computed: {
    isDataEnable() {
      return this.isDataNode(_.get(this.currentNode, 'def'));
    },
  },
  directives: {
    Draggable,
  },
  components: {
    NodeDataValue,
    NodeFormulaRender,
    BuilderNodesProp,
    BuilderNodesAdd,
    BuilderNodesAddTools,
    BuilderNodesLowcode,
    BuilderNodePropext,
    BuilderCompsCloud,
    PageItemPicker
  },
  mounted() {
    this.$nextTick(() => {
      this.nodeTreeDragProp.handle = this.$refs.nodeTreeDragHandler;
      this.nodeTreeDragProp.onDragStart = () => {
        this.moving = true;
      }

      this.nodeTreeDragProp.onDragEnd = (positionDiff, absolutePosition, event) => {
        this.moving = false;

        if(absolutePosition && absolutePosition.top < 0) {
          this.$el.style.top = "0px";
        }

        if(absolutePosition && absolutePosition.left < 100) {
          this.$el.style.left = "0px";
          this.$el.style.top = "41px";
          this.panelFixed = true;

          this.$emit('pinMenuChange', true);
        } else {
          this.panelFixed = false;
          this.$emit('pinMenuChange', false);
        }
      }
    })
  },
  watch: {
    currentItemElCode(code) {
      this.$refs.nodesTree.setCurrentKey(code);

      if(!this.isNodeHover) this.expandKeys = [ code ];

      // this.initElemCurrentNode();

      let nodeData = this.$utils.getTreeData(this.elemNodes, "code", this.currentItemElCode);
      let currentEleData = _.get(nodeData, 'def');
      this.currentEleData = currentEleData || {};
      this.currentNode = nodeData;
      this.popData = nodeData;
      this.handleTempExpand();
      this.showNodeActionPopover();
    },
    nodesPropShow(val) {
      if(!val) return;
      let screenWidth = window.screen.width;
      let rect = this.$el.getBoundingClientRect();
      // let width = rect.width;
      // let height = rect.height;
      let left = rect.left;
      let right = rect.right;
      let distance = 350 - (screenWidth - right);

      if(distance > 0 && this.$el && this.$el.style) {
        this.$el.style.left = `${ left - distance }px`;
      }
    }
  },
  methods: {
    ...mutil,
    onPosChanged(positionDiff, absolutePosition, event) {   // 解决超出边界无法找到面板的bug
      this.hideNodeMorePopover();
    },
    hasActionLimitData(data, actionType = 'div') {
      // let popData = this.popData;
      let nodeType = _.get(data, "def._node") || _.get(data, "def._component");
      // let parentDef = _.get(this.popData, "parentDef");
      // if(_.indexOf([ 'div', 'text', 'icon', 'img', 'video', 'button' ], actionType) >= 0) {
      if(_.indexOf([ 'text', 'icon', 'img', 'video' ], nodeType) >= 0) {
        return false;
      }
      return true;
    },
    hasActionLimit(actionType) {
      return this.hasActionLimitData(this.popData, actionType)
    },
    getCurrentItem(node) {
      if(!node) return;

      let isRoot  = _.get(node, "data.isRoot");
      let item    = _.get(node, "data.item");
      let items   = _.get(node, "data.items");
      let parent  = _.get(node, "parent");

      if(isRoot) return { item, items };

      return this.getCurrentItem(parent);
    },
    clearSelectEleNodeHoverTimeout() {
      if(this.hoverTimeout) {
        clearTimeout(this.hoverTimeout);
        this.hoverTimeout = null;
      }
    },
    handleSelectEleNodeHover(data, node) {
      this.$emit('hoverElenode', data);
    },
    handleSelectEleNodeClick(data, node, vueObj, isHover = false) {
      // console.log(`===> isHover: ${ isHover }`);
      let nodeCode =  _.get(data, 'code');
      this.isNodeHover = isHover || false;

      if(!this.isNodeHover) this.expandKeys = [ nodeCode ];

      this.$emit('selectElenode', data);

      let info = this.getCurrentItem(node);

      if(info) this.$emit("selectItem", info);
      // this.currentItemElCode = _.get(data, 'code');

      this.popData = data;

      let currentCode = _.get(data, "code");
      let popCode = _.get(this.popData, "code");

      if(currentCode !== popCode) {
        this.hideNodeMorePopover();
      }
    },
    showNodeMorePopover(e, data, isActionBtn = false) {

      let $npop = this.$refs.nodeMorePopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);

      if(!isActionBtn) {
        this.popData = data;
      }

      // this.hideNodeDataPopover();
      this.$nextTick(() => {
        //显示新的
        // console.log(typeof this.$refs.nodesTreeContainer);
        let $refer = isActionBtn ? e.target.parentNode : this.$refs.nodesTreeContainer;
        $npop.referenceElm = $npop.$refs.reference = $refer // e.target.parentNode;
        $npop.showPopper = true;
        $npop.$emit('input', true);
        $npop.doShow();
      })
    },
    hideNodeMorePopover() {
      let $npop = this.$refs.nodeMorePopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);
    },
    getClosestVisibleEle(ele, idx = 0) {
      if(!ele) return null;
      if(idx > 5) return null;
      if(!idx) idx = 0;

      let style = window.getComputedStyle(ele);
      if(_.get(style, 'display') === 'none') {
        return this.getClosestVisibleEle(ele.parentNode, ++idx);
      } else {
        return ele;
      }
    },
    showNodeActionPopover() {
      let $npop = this.$refs.nodeActionPopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);

      let focusCode = this.currentItemElCode;
      if(!focusCode) return;

      let $eles = document.querySelectorAll(`[j-name=${ focusCode }]`);
      let $refer = this.getClosestVisibleEle(_.get($eles, '[0]'));
      if(!$refer) return;

      console.log($refer)

      // this.hideNodeDataPopover();
      this.$nextTick(() => {
        //显示新的
        // console.log(typeof this.$refs.nodesTreeContainer);
        $npop.referenceElm = $npop.$refs.reference = $refer; // e.target.parentNode;
        $npop.showPopper = true;
        $npop.$emit('input', true);
        $npop.doShow();
      })
    },
    hideNodeActionPopover() {
      let $npop = this.$refs.nodeActionPopover;

      $npop.showPopper = false;
      $npop.doClose();
      $npop.doDestroy(true);
    },
    handleShowNodeIconWin() {
      this.$IconSpace({
        onSelect: (icon) => {
          if(this.currentEleData && this.currentEleData._ss) {
            this.currentEleData._ss.icon = icon;
          }
        }
      });
    },
    handleShowNodeImgWin() {
      this.$FileSpace({
        onSelect: (img) => {
          let filePath = _.get(img, "file_path");
          if(this.currentEleData && this.currentEleData._ss && filePath) {
            this.currentEleData._ss.image = filePath;
          }
        }
      });
    },
    handleClearNodeProp(type) {
      if(!this.currentEleData || !this.currentEleData._ss) return;
      if(type === 'icon') {
        this.currentEleData._ss.icon = "";
      } else if(type === 'img') {
        this.currentEleData._ss.image = "";
      }
    },
    isFixNode(data) {
      let def = _.get(data, "def")
      let code = _.get(data, "code") || _.get(def, "_code");
      let isFix = _.get(def, "_fix");

      if(!code || isFix) return true;

      let nodes = this.$utils.getTreePath(code, this.elemNodes, "code");

      let idx = _.findIndex(nodes, { _fix: "all" });

      return idx >= 0;
    },
    getCurrentItemIndex() {
      let itemCode = _.get(this.currentItem, 'page_item_code');
      if(!itemCode) return -1;
      return _.findIndex(this.currentItems, { page_item_code: itemCode });
    },
    handleRemoveSelected() {
      this.handleRemove(this.popData);
    },
    handleRemoveItem(item) {
      let itemCode = _.get(item, 'page_item_code');
      if(!itemCode) return -1;
      let idx = _.findIndex(this.currentItems, { page_item_code: itemCode });

      if(idx < 0) return;

      this.currentItems.splice(idx, 1);
      // this.updateMask();
      // this.handleSelectItem();
      // this.$forceUpdate();
      this.$emit("selectItem", {});
      this.$emit("eleNodeTreeChange");
    },
    handleRemove(data) {
      if(!data) return;

      if(data.isRoot) {
        return this.handleRemoveItem(data.item);
      }

      let def = _.get(data, "def");
      let parentDef = _.get(data, "parentDef");
      let code = _.get(data, "code");

      if(!def || !parentDef || !code) return;

      for(let p in parentDef) {
        let child = _.get(parentDef, p);

        if(child && child._code && child._code === code) {
          delete parentDef[ p ];
          break;
        }
      }

      let expandKeys = [ _.get(parentDef, "_code") ];

      for(let p in parentDef) {
        let child = _.get(parentDef, p);
        if(child && child._code) expandKeys.push(child._code);
      }
      this.hideNodeMorePopover();
      this.hideNodeActionPopover();
      this.$emit("changeElemNodes");

      this.$nextTick(() => {
        this.expandKeys = expandKeys;
      })
    },
    handleNameChg(data) {

      if(!data) return;

      let name = _.get(data, "name");
      let def = _.get(data, "def");

      data.nameEditing = false;

      if(!def) return;
      def._name = name;
    },
    getNodeRootCode(node) {
      let root = this.getItemRootByNode(node);
      return _.get(root, "data.code");
    },
    allowDrop(draggingNode, dropNode, type) {
      let dropData = _.get(dropNode, "data");
      let dropDataDef = _.get(dropData, "def");
      let dropNodeIsRoot = _.get(dropData, "isRoot");
      let dropNodeName = _.get(dropData, "name");
      let dropNodeType = _.get(dropDataDef, "_node");
// console.log("-------------------->>>>>>>>>----------------------");
// console.log(draggingNode, dropNode, type)
// console.log(draggingNode.parent);
      let dragIsRoot = _.get(draggingNode, "data.isRoot");

      if(type === 'inner') {
        if(_.indexOf([ 'text', 'icon', 'img' ], dropNodeType) >= 0) return false;
        if(dragIsRoot) {
          // 只能放 layout 下
          if(dropNodeName && dropNodeName !== 'jzlLayout') {
            return false;
          }
        } else {
          // layout 下只能是组件
          if(!dropNodeName || dropNodeName === 'jzlLayout') {
            return false;
          }
        }

        // 不能放 grid, slider 的wrap 中
        let subs = _.get(dropData, "children");

        if(subs && subs.length) {
          let hasMulti = _.find(subs, s => {
            let st = _.get(s, "def._node");
            return st === 'grid' || st === 'slider';
          });

          if(hasMulti) return false;
        }

      } else if(type === "prev" || type === 'next') {
        if(dragIsRoot && !dropNodeIsRoot) return false;
        // item 只能在根下或者根同级。
        if(!dragIsRoot && dropNodeIsRoot) return false;

        // let parentIsRoot = _.get(dropNode, "parent.data.def._node");
        let parentName = _.get(dropNode, "parent.data.name");
        let nodeType = _.get(dropDataDef, "_node");

        // layout 下只能是组件
        if((parentName === 'jzlLayout' || !parentName) && !dropNodeIsRoot) return false;
        if(nodeType === 'grid' || nodeType === 'slider') return false;
      }

      if(!dragIsRoot) {
        // 普通元素只能同组件下移动
        let dragRootCode = this.getNodeRootCode(draggingNode);
        let dropRootCode = this.getNodeRootCode(dropNode);

        if(!dragRootCode || dragRootCode !== dropRootCode) return false;
      }

      return true;
    },
    allowDrag(draggingNode) {
      // console.log(draggingNode)
      let nodeData = _.get(draggingNode, "data");
      let nodeDef = _.get(nodeData, "def");
      let isRoot = _.get(nodeData, "isRoot");
      let nodePropName = _.get(nodeData, "propName");
      // let nodePropPath = _.get(nodeData, "propPath");
      let nodeType = _.get(nodeDef, "_node");

      return isRoot || (nodeType !== 'grid' && nodeType !== 'slider' && nodePropName !== 'box_style' && nodePropName !== 'box_style'/* && nodePropPath !=='box_style.header'*/);
    },
    handleDropDone(draggingNode, dropNode, type, event) {
      // console.log(draggingNode, dropNode, type);
      this.$emit("node-drop-done", { draggingNode, dropNode, type, event});
    },

    getPageTitle(page, dftTitle) {
      return _.get(page, "page_name") || dftTitle
    },
    isEmptyPage(info) {
      return !info || !info.page_id;
    },
    closeOver() {
      // this.nodesPropShow = false;
      this.compAddPanelShow = false;
    },
    hideNodeProp() {
      this.nodesPropShow = false;
    },
    showNodeProp(propTab = 'style', isHover = false) {
      this.nodesPropShow = true;
      this.collapse = false;

      if(!isHover || propTab !== 'style' || this.propTab !== 'hover') {
        this.propTab = propTab;
      }
    },
    toggleNodeProp() {
      this.nodesPropShow = !this.nodesPropShow;

      if(this.nodesPropShow) {
        // this.propTab = 'style';
      }
      this.$emit('pinPropChange', this.nodesPropShow);
    },
    handleCollapseSwitch() {
      this.collapse = !this.collapse;
    },
    handleTempExpand() {
      this.tempExpand = true;

      if(this.tempExpandTimer) clearTimeout(this.tempExpandTimer);
      this.tempExpandTimer = setTimeout(() => { this.tempExpand = false }, 1200);
    },
    handleMouseEnter() {
      this.hoverExpand = true;
    },
    handleMouseLeave() {
      if(this.hoverExpandTimer) clearTimeout(this.hoverExpandTimer);
      this.hoverExpandTimer = setTimeout(() => { this.hoverExpand = false }, 1000);

      this.$emit('hoverElenode', null);
    },
    handlePropTabChange(tab) {
      this.propTab = tab;
    },
    copyNode(data) {
      let prop = _.get(data, "propName");
      let def = _.cloneDeep(_.get(data, "def"));

      if(!prop || !def) return;

      this.resetCode(def);

      let str = JSON.stringify({ prop, def });
      this.$utils.copyText(str);
    },
    async pasteNode(data) {
      let copiedText = await navigator.clipboard.readText();

      try {
        let json = JSON.parse(copiedText);
        let prop = _.get(json, "prop");
        let def = _.get(json, "def");

        if(!prop || !def) return;

        let xDef = _.get(data, "def");

        if(xDef[ prop ]) {
          prop = this.$utils.getNanoid(8);
        }

        xDef[ prop ] = def;

        this.$emit("eleNodeTreeChange")
      } catch (e) {}

    },
    pasteNodeReplace(data) {

    },
    copyItem() {
      let idx = this.getCurrentItemIndex();

      if(idx < 0) return;

      let orig = _.cloneDeep(this.currentItems[ idx ]);
      let code = this.$utils.getNanoid(8);
      let citem = _.defaultsDeep({
        page_item_code: code,
        alias: this._getAlias(code, this.items),
        project_id: this.projectId,
        module_name: code,
        i: code
      }, orig);   // _.merge({}, this.items[index]);

      delete citem.page_item_id;

      // let box_style = _.get(citem, "box_style");
      let ele_style = _.get(citem, "ele_style");

      // this.resetCode(box_style);
      this.resetCode(ele_style);

      this.currentItems.splice(idx + 1, 0, citem);
      this.$emit("eleNodeTreeChange")
    },
    handleCtrlC(data) {
      if(!data) return;
      if(data.isRoot) {
        this.copyItem(data);
      } else {
        this.copyNode(data);
      }
    },
    handleAddItem(menu, type) {

      let def = _.get(menu, "def");
      let vars = _.get(menu, "vars");
      let component = _.get(menu, 'component');

      if(!def) return;

      let eleDef = _.cloneDeep(def);
      let wrapDef = eleDef;
      let varsDef = _.cloneDeep(vars);

      if(component !== 'div' && component !== 'box') {
        if(type === 'box') {
          wrapDef = this.getNodeCompTpl('box');

          wrapDef.body[ component ] = eleDef;
        } else if(type === 'div') {
          wrapDef = this.getNodeCompTpl('div');
          wrapDef[ component ] = eleDef;
        }
      }

      //
      if(this.pageType == 1) {
        let width = _.get(wrapDef._ss, 'width') || 300;
        let height = _.get(wrapDef._ss, 'height') || 300;

        if(component === 'button') {
          width = 200;
          height = 50;
        } else if(component === 'icon') {
          width = 50;
          height = 50;
        } else if(component === 'text') {
          width = 300;
          height = 50;
        } else if(component === 'img') {
          width = 300;
          height = 300;
        } else if(component === 'c$navComp') {
          width = 500;
          height = 100;
        }

        if(!wrapDef._ss) wrapDef._ss = {};
        wrapDef._ss.position = "absolute";
        wrapDef._ss.width = width;
        wrapDef._ss.height = height;

        let pageWidth = this.pageWidth || 1920;
        let pageHeight = this.pageHeight || 1080;
        if(!_.hasIn(wrapDef._ss, 'left')) wrapDef._ss.left = (pageWidth - width) / 2;
        if(!_.hasIn(wrapDef._ss, 'top')) wrapDef._ss.top = (pageHeight - height) / 2;

        // wrapDef._ss.left = (1920 - width) / 2;
        // wrapDef._ss.top = (1080 - height) / 2;
      }

      this.$emit("create-page-item", {
        component: 'JzlItemComp',
        micro: true,
        // icon: 'fa fa-font',
        name: '模块',

        ele_style: wrapDef,    // this.getNodeCompTpl('div'),
        vars: varsDef
      });

      this.compAddPanelShow = false;
    },
    handleAddChildNodeCloud(compInfo) { // 云端组件作为 micro comp
      let comp_lib = _.get(compInfo, "comp_lib");
      let comp_name = _.get(compInfo, "comp_name");
      let comp_def = _.get(compInfo, "comp_def");

      if(!this.popData) return;

      let def = _.get(this.popData, "def");
      let name = this.getUniqNewPropName(def);

      if(!def) return;

      let newInfo = this.getNodeCompDefInfo(comp_def, this.currentItem);
      let info = _.get(newInfo, 'ele_style');
      let vars = _.get(newInfo, 'vars');
      let _code = this.$utils.getNanoid(10);

      this.currentItem.vars = (this.currentItem.vars || []).concat(vars);

      info._code = _code;
      info._lib = comp_lib;
      info._node = comp_name;

      if(!def._sort) {
        this.$set(def, '_sort', []);
        def._sort = [];
      }
      def._sort.push(name);
      this.$set(def, name, info);
      def[ name ] = info;

      // this.hideNodeMorePopover();
      this.$emit("changeElemNodes");

      this.$nextTick(() => {
        setTimeout(() => {
          this.$emit("selectItem", {
            targetEleName: _code,
            item: this.currentItem,
            items: this.currentItems
          });
        }, 100)
      });
    },
    handleShowMicroComps() {
      this.collapse = false;
      this.compAddPanelShow = true;
    },
    handleShowCloudComps(isCreateMicroComp = false) {
      this.collapse = false;
      this.compPanelShow = true;
      this.isCreateMicroComp = isCreateMicroComp === true;
      // this.$emit('show-cloud-comps')
    },
    handleCreateCloudComp(compInfo) {
      if(this.isCreateMicroComp) {
        this.handleAddChildNodeCloud(compInfo);
      } else {
        // this.$emit("create-page-item", comp);
        let comp_lib = _.get(compInfo, "comp_lib");
        let comp_name = _.get(compInfo, "comp_name");
        let comp_def = _.get(compInfo, "comp_def");

        let info = _.get(comp_def, 'ele_style');
        let vars = _.get(comp_def, 'vars');
        let _code = this.$utils.getNanoid(10);
        let component = _.get(comp_def, "component") || comp_name;

        info._code = _code;
        info._lib = comp_lib;
        info._node = comp_name;
        info._name = `组件-${ comp_name }`;

        let eleDef = _.cloneDeep(info);
        let varsDef = _.cloneDeep(vars);
        let wrapDef = this.getNodeCompTpl('div');
        wrapDef[ component ] = eleDef;

        this.$emit("create-page-item", {
          component: 'JzlItemComp',
          micro: true,
          // icon: 'fa fa-font',
          name: '模块',

          ele_style: wrapDef,    // this.getNodeCompTpl('div'),
          vars: varsDef
        });
      }

      this.$jui.toast('添加成功！');
    },
    handleCloseCompPanel() {
      this.compAddPanelShow = false;
    },
    handleClearTagValue(nodeData) {
      if(nodeData && nodeData._value) {
        nodeData._value = "";
      }
    },
    handlePageItemSelectShow() {
      this.pageItemSelectWinShow = true;
    },
    handleCopyItem(item) {
      let code = this.$utils.getNanoid(10);
      let copyItem = _.defaultsDeep({
        page_item_code: code,
        alias: this._getAlias(code),
        project_id: this.projectId,
        module_name: code,
        i: code
      }, item);   // _.merge({}, this.items[index]);

      delete copyItem.page_item_id;

      let boxStyle = _.get(copyItem, "box_style");
      let eleStyle = _.get(copyItem, "ele_style");
      this.resetCode(boxStyle);
      this.resetCode(eleStyle);

      this.handleMenuClick(copyItem);
      this.pageItemSelectWinShow = false;
    },
    handleReferItem(item) {
      let code = this.$utils.getNanoid(10);
      let referItem = _.defaultsDeep({
        page_item_code: code,
        alias: this._getAlias(code),
        module_name: code,
        i: code,
        project_id: this.projectId,
        refer: item,
        refer_item_id: _.get(item, 'page_item_id')
      }, _.cloneDeep(referDef));

      this.handleMenuClick(referItem);
      this.pageItemSelectWinShow = false;
    },
    isCurrentSelected(data) {
      let isRoot = _.get(data, "isRoot");
      let pic = _.get(data, "item.page_item_code");
      let pic2 = _.get(this.currentItem, "page_item_code");

      return isRoot && pic && pic === pic2;
    }
  }
}
</script>
